package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"os"
	"time"

	"github.com/faiface/beep"
	"github.com/faiface/beep/mp3"
	"github.com/faiface/beep/speaker"
	"github.com/viert/go-lame"
)

// func init() {
// 	err := speaker.Init(sampleRate, sampleRate)

// 	if err != nil {
// 		panic(err)
// 	}
// }

type Mp3File struct {
	enc    *lame.Encoder
	fp     *os.File
	Writer *bufio.Writer
	Reader *bufio.Reader
	name   string
	s      beep.StreamSeekCloser
	f      beep.Format
}

func NewAudioFile() *Mp3File {
	return &Mp3File{}
}

func (p *Mp3File) Open(name string) error {
	p.name = name
	var err error
	p.fp, err = os.Open(p.name)
	if err != nil {
		return err
	}
	p.s, p.f, err = mp3.Decode(p.fp)
	if err != nil {
		return err
	}
	return nil
}

// var speakerNeedClose = false
var AudioOnExit = func() {
	// if speakerNeedClose {
	// 	speaker.Close()
	// }

}

func (p *Mp3File) Read(out []int16) (int, error) {

	buf := make([][2]float64, len(out))
	n, ok := p.s.Stream(buf)
	if !ok {
		return 0, errors.New("EOF")
	}
	if n < len(out) {
		for i := n; i < len(out); i++ {
			out[i] = 0
		}
	}
	for i := 0; i < n; i++ {
		out[i] = int16(buf[i][0]*10000+buf[i][1]*10000) / 2
	}
	//println("len:", n)
	return n, nil
}

func (p *Mp3File) Play() (time.Duration, error) {

	//speakerNeedClose = true
	speaker.Play(p.s)

	return p.f.SampleRate.D(p.s.Len()), nil
}

func (p *Mp3File) Create(name string) error {
	var err error
	p.fp, err = os.Create(name)
	if err != nil {
		return err
	}
	p.enc = lame.NewEncoder(p.fp)

	p.enc.SetNumChannels(1)
	p.enc.SetInSamplerate(44100)
	p.enc.SetMode(lame.MpegMono)
	p.enc.SetQuality(2)
	p.enc.SetWriteID3TagAutomatic(true)
	//p.enc.SetMode(lame.MpegMono)
	p.Writer = bufio.NewWriter(p.enc)
	return nil
}

func (p *Mp3File) Close() {

	speaker.Clear()

	//speaker.Close()
	//speaker.Init(sampleRate, sampleRate)

	if p.enc != nil {
		p.enc.Flush()
		p.enc.Close()
		p.fp.Close()
	}

}

func (p *Mp3File) Write(buf []int16) error {
	w := bytes.NewBufferString("")
	err := binary.Write(w, binary.LittleEndian, buf)
	if err != nil {
		return err
	}
	//var n int
	_, err = p.Writer.Write(w.Bytes())
	if err != nil {
		return err
	}
	//println("write len:", n)
	err = p.Writer.Flush()
	return err
}
